<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue3响应式原理</title>
</head>
<body>
  <script type="text/javascript">
    // 数据源
    let person = {
      name: '张三',
      age: 20
    };

    // 模拟Vue2响应式处理
    /* let p = {};
    Object.keys(person).forEach(key => {
      Object.defineProperty(p, key, {
        configurable: true,
        get() {
          console.log(`获取了${key}属性`);
          return person[key];
        },
        set(newVal) {
          console.log(`设置了${key}属性，新的值是${newVal}`);
          person[key] = newVal;
        }
      });
    }); */

    // 模拟Vue3响应式处理
    /* function reactive(obj) {
      return new Proxy(obj, {
        get(target, key) {
          console.log(`获取了${key}属性`);
          return target[key];
        },
        set(target, key, newVal) {
          console.log(`设置了${key}属性，新的值是${newVal}`);
          target[key] = newVal;
          return true; // 表示设置成功
        }
      });
    } */

    // 代理对象
    let p = new Proxy(person, {
      // 读取数据
      get(target, key) {
        console.log(`获取了${key}属性`);
        // return target[key];
        return Reflect.get(target, key); // 等同于上面一行代码
      },
      // 新增数据、修改数据
      set(target, key, newVal) {
        console.log(`设置了${key}属性，新的值是${newVal}`);
        // target[key] = newVal;
        // return true; // 表示设置成功
        return Reflect.set(target, key, newVal); // 等同于上面两行代码
      },
      // 删除数据
      deleteProperty(target, key) {
        console.log(`删除了${key}属性`);
        // return delete target[key];// 表示删除成功
        return Reflect.deleteProperty(target, key); // 等同于上面一行代码
      }
    });

    let obj = { a: 10, b: 20 };

    // 需要额外处理报错
    /* try {
      Object.defineProperty(obj, 'c', {
        get() {
          return 3;
        }
      });
      // 相同属性只能定义一次，后定义的无法覆盖先定义的，会报错：Uncaught TypeError: Cannot redefine property: c
      Object.defineProperty(obj, 'c', {
        get() {
          return 4;
        }
      });
    } catch (error) {
      console.log(error);
    } */


    // Reflect反射对象
    // 使用Reflect.defineProperty不会报错，但后定义的无法覆盖先定义的，保证代码的健壮性
    /* const x1 = Reflect.defineProperty(obj, 'c', {
      get() {
        return 3;
      }
    });

    // 可以多次定义同一属性，后定义的无法覆盖先定义的
    const x2 = Reflect.defineProperty(obj, 'c', {
      get() {
        return 4;
      }
    });

    if(x2) {
      console.log('第二次定义成功');
    } else {
      console.log('第二次定义失败');
    } */



  </script>
</body>
</html>